package middleware

import (
	"errors"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"hr/config"
	"hr/service"
	"hr/utils"
	"strings"
	"time"
)

//此项为基本jwt认证模型
type JwtModel struct {
	jwt.StandardClaims
	Adminid	string
	Username	string
}

//Jwt中间件校验
func RegisterJwtAuth()gin.HandlerFunc{
	return func(c *gin.Context){
		token := c.Request.Header.Get("Access-Token")
		if !utils.IsStringEmpty(token){
			//校验token是否正确
			u,err := ParseToken(token)
			if err != nil{
				utils.EchoAccessError(c,err.Error())
				c.Abort()
				return
			}

			_, err = service.FileCache.Fetch(u.Id)
			if err != nil {
				utils.EchoAccessError(c,err.Error())
				c.Abort()
				return
			}

		}else{
			utils.EchoAccessError(c,"认证校验失败")
			c.Abort()
			return
		}
	}
}

//创建Jwt令牌
func CreateJWT(model JwtModel) (string,error){
	token := jwt.NewWithClaims(jwt.SigningMethodHS256,model);
	tokenString,err := token.SignedString([]byte(config.AppConfig.Jwt.SecretKey));
	if err != nil{
		return "",err;
	}else{
		return tokenString,err
	}
}

//解析令牌
func ParseToken(tokenString string) (*JwtModel, error) {
	tokenClaims, err := jwt.ParseWithClaims(tokenString, &JwtModel{}, func(token *jwt.Token) (interface{}, error) {
		return []byte([]byte(config.AppConfig.Jwt.SecretKey)), nil
	})
	if tokenClaims == nil {
		return nil, errors.New("会话令牌无效")
	}
	if claims, ok := tokenClaims.Claims.(*JwtModel); ok && tokenClaims.Valid {
		if claims.VerifyExpiresAt(time.Now().Unix(),true) == false{
			return &JwtModel{},errors.New("会话令牌已过期")
		}
		if claims.VerifyNotBefore(time.Now().Unix(),true) == false{
			return &JwtModel{},errors.New("会话令牌生成时间不正确！")
		}
		if claims.VerifyIssuer("hsyedu.com",true) == false{
			return &JwtModel{},errors.New("令牌生成使用者不正确！")
		}

		return claims, nil
	} else {
		return &JwtModel{}, err
	}
}

func GetCurrentUserId(c *gin.Context) (uint,error) {
	token := c.Request.Header.Get("Access-Token")
	if utils.IsStringEmpty(token) {
		return 0, errors.New("token is empty")
	}
	u,err := ParseToken(token)
	if err != nil{
		return 0,err
	}

	saveUserId := strings.ReplaceAll(u.StandardClaims.Id,"user_","")

	userId := cast.ToUint(saveUserId)
	return userId, nil
}